using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using GuavaData;

namespace GuavaLib
{
    public partial class GForm : Form, GuavaForm
    {
        List<Guava> GuavaComponents;
        GSeed gs;
        protected Guid thisID, thisFK;
        string gname;
        protected bool bNew;
        protected int row;

        public event GuavaData.SignalToPersist PersistSignal;

        public GForm()
        {
            this.GuavaComponents = new List<Guava>();
            InitializeComponent();
        }

        public GForm(Guid id, Guid fk, bool bNew, GSeed gs) : this()
        {
            this.Init(id, fk, bNew, gs);
        }

        protected void Init(Guid id, Guid fk, bool bNew, GSeed gs)
        {
            this.gs = gs;
            thisID = id;
            thisFK = fk;
            this.bNew = bNew;
            if (id.Equals(fk))
            {
                // We have a single-launch situation
                row = AppData.FetchRowOrCreate(this.GName, id);
                AppData.ds.Tables[this.GName].Rows[row].AcceptChanges();
            }
            else if (bNew)
            {
                // We have a multiple-launch, "new object" situation
                row = AppData.CreateRow(this.GName, id, fk);
                AppData.CommitRow(this.GName, id, DMLType.INSERT);
            }
            else
            {
                // We have a multiple-launch, "edit object" situation
                row = AppData.FetchRow(this.GName, id);
            }
            
            // Attach Data
            foreach (Guava cc in GComponents) cc.GBind(this.GName, row);
            DataSet ds = AppData.ds;
            CurrencyManager cm = (this.BindingContext[AppData.ds.Tables[this.GName]]) as CurrencyManager;
            cm.Position = row;

            // Test the GSeed - see if we need to make some action
            if (this.gs == null)
            {
                // Create a new seed, then add the current form to the seed frames
                this.gs = new GSeed(this.GetType().FullName, AppData.dbsource, AppData.dbcatalog);
                this.gs.Push(new GSeedFrame(this.ID, this.GName));
            }
            else if (this.gs.NeedToAdvance)
            {
                // Action!
                
                // If the "need to advance" flag is set, then some automation is necessary
                // Use the current frame's information to find the appropriate launch mechanism
                GSeedFrame gsfTemp = this.gs.PeekAdvance();
                Guid next = this.gs.NextId;

                // Loop through the gsfTemp controls list to find the right launcher
                Guava gTemp = this;
                foreach (string c in gsfTemp.controls)
                {
                    gTemp = gTemp[c];
                    if (gTemp == null) throw new Exception("Could not find control path " + String.Join("/", gsfTemp.controls.ToArray()) + " on form " + this.GName);
                }

                // gTemp is now the control that was used to launch the next form, or held the mark
                // Use gTemp's machinery to launch the next form or highlight the mark
                if (this.gs.NeedToAdvance)
                {
                    if (!(gTemp is GuavaLaunchBase)) throw new Exception("Control " + String.Join("/", gsfTemp.controls.ToArray()) + " is not a launchable control.");
                    GuavaLaunchBase glb = gTemp as GuavaLaunchBase;

                    // Set the control's internal ID to the correct value and launch
                    // Notice that the form is necessarily NOT a new object
                    glb.SetObject(next);
                    glb.LaunchForm(next, gsfTemp.form, false);
                }
            }
            else
            {
                // Add the current form to the seed frames
                this.gs.Push(new GSeedFrame(this.ID, this.GName));
            }
        }

        #region GuavaForm Members

        [Browsable(false)]
        public LaunchType LType
        {
            get
            {
                return LaunchType.NA;
            }
        }

        [Browsable(false)]
        public ControlType CType
        {
            get
            {
                return ControlType.Entity;
            }
        }

        [Browsable(false)]
        public string GText
        {
            get
            {
                return this.Text;
            }
        }

        public string GName
        {
            get
            {
                if (gname == null) return this.Name;
                return gname;
            }
            set
            {
                gname = value;
                return;
            }
        }

        [Browsable(false)]
        public Point GLocation
        {
            get { return this.Location; }
        }

        [Browsable(false)]
        public Size GSize
        {
            get { return this.Size; }
        }

        [Browsable(false)]
        public List<Guava> GComponents
        {
            get
            {
                List<Guava> lg = new List<Guava>();
                
                foreach (Control c in this.Controls)
                    if (c is Guava) lg.Add((Guava) c);
                foreach (Guava g in this.GuavaComponents)
                    lg.Add((Guava) g);
                
                return lg;
            }
        }

        public void GBind(string table, int i)
        {
            return;
        }

        [Browsable(false)]
        public Guid ID
        {
            get
            {
                return this.thisID;
            }
            set
            {
                this.thisID = value;
            }
        }

        public void Save()
        {
            AppData.CommitRow(this.GName, this.thisID, DMLType.UPDATE);
            AppData.ds.Tables[this.GName].AcceptChanges();
            this.gs.Pop();
            this.DialogResult = DialogResult.OK;
            if (this.PersistSignal != null) this.PersistSignal(this, new PersistSignalEventArgs(true));
            this.Close();
        }

        public void Cancel()
        {
            if (this.thisID == this.thisFK)
                AppData.ds.Tables[this.GName].Rows[this.row].RejectChanges();
            else if (bNew)
            {
                AppData.CommitRow(this.GName, this.thisID, DMLType.DELETE);
                AppData.ds.Tables[this.GName].RejectChanges();
            }
            else
                AppData.ds.Tables[this.GName].Rows[this.row].RejectChanges();
            this.gs.Pop();
            this.DialogResult = DialogResult.Cancel;
            if (this.PersistSignal != null) this.PersistSignal(this, new PersistSignalEventArgs(false));
            this.Close();
        }

        [Browsable(false)]
        public string GDefault
        {
            get { return null; }
        }

        [Browsable(false)]
        public string GToolTip
        {
            get { return null; }
        }

        [Browsable(false)]
        public GuavaData.Domain.Domain GDomain
        {
            get
            {
                return new GuavaData.Domain.UniqueIdentifier();
            }
        }

        [Browsable(false)]
        public ToolTip GToolTipProvider
        {
            get { return this.toolTip1; }
        }

        [Browsable(false)]
        public GSeed GS
        {
            get { return gs; }
            set { gs = value; }
        }

        [Browsable(false)]
        public bool HasData
        {
            get
            {
                DataTable dt = AppData.ds.Tables[this.GName];
                DataRow dr = dt.Rows[row];

                foreach (DataColumn dc in dt.Columns)
                {
                    if (dr[dc] is DBNull) continue;
                    if (dc.ColumnName == "id") continue;
                    if (dc.ColumnName == "fk") continue;

                    // For any column, if that column in the row has data, return true
                    if (dc.DataType.FullName == "System.Boolean")
                    {
                        // 'true' counts as data, 'false' does not
                        bool b = (bool)dr[dc];
                        if (b) return true;
                    }
                    else
                    {
                        // If it gets here, then there must be data
                        return true;
                    }
                }

                return false;
            }
        }

        public Guava this[string s]
        {
            get
            {
                foreach (Guava g in this.GComponents) if (g.GName == s) return g;
                return null;
            }
        }

        public void AddGComponent(Guava g)
        {
            this.GuavaComponents.Add(g);
        }
        #endregion
        
        protected virtual bool ValidateContents()
        {
            return true;
        }

        private void btnGFormOK_Click(object sender, EventArgs e)
        {
            if (!this.ValidateContents()) return;

            try
            {
                this.Save();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
            }
        }

        private void btnGFormCancel_Click(object sender, EventArgs e)
        {
            try
            {
                this.Cancel();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
            }
        }
    }
}
